﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
using System.Collections;
using System.IO;

namespace SharePointUsers
{
    public partial class MainForm : Form
    {
        #region Private Members
        //Prepare SPU object
        SPUmanager spuManagerObj = new SPUmanager();
        int SiteCount = 0;
        int SelectedSiteCount = 0;
        int AppCount = 0;
        bool ApplicationsLoaded = false;
        private bool UpdatingNode = false;
        #endregion
        public MainForm()
        {
            InitializeComponent();
            
        }
        private DataTable GetFarmStatistics(SPWebService CurrentFarm)
        {
            DataTable Summary = new DataTable("Farm Statistics");

            Summary.Columns.Add("Applications");
            Summary.Columns.Add("Sites");
            int Application = 0;
            int SiteCollections = 0;
            foreach (SPWebApplication wa in CurrentFarm.WebApplications)
            {
                Application++;
                foreach (SPContentDatabase contentdb in wa.ContentDatabases)
                {
                    SiteCollections += contentdb.CurrentSiteCount;
                }
            }
            Summary.Rows.Add(Application, SiteCollections);

            return Summary;

        }
        private void LoadApps()
        {
            SPWebService CurrentFarm = SPWebService.ContentService;
            SPFarm FarmObj = SPFarm.Local;

            if (CurrentFarm == null || FarmObj == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));
            UpdatingNode = true;
            treeViewSites.Nodes.Clear();

            //Create the farm root node
            TreeNode FarmNode = new TreeNode(FarmObj.Name);
            FarmNode.ImageIndex = 42;
            FarmNode.Checked = true;
            FarmNode.Tag = SPdalHelper.PopulateFarm(FarmObj);
            treeViewSites.Nodes.Add(FarmNode);

            foreach (SPWebApplication wa in CurrentFarm.WebApplications)
            {
                TreeNode App = new TreeNode(wa.Name);
                //Web application icon
                App.ImageIndex = 39;
                App.Checked = true;
                App.Tag = SPdalHelper.PopulateApplication(wa);
                FarmNode.Nodes.Add(App);
                AppCount++;
            }
            ApplicationsLoaded = true;
            UpdatingNode = false;
            UpdateSiteCount();
        }
        private void LoadFarm()
        {
            SPWebService CurrentFarm = SPWebService.ContentService;
            SPFarm FarmObj = SPFarm.Local;

            if (CurrentFarm == null || FarmObj == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));
            UpdatingNode = true;
            treeViewSites.Nodes.Clear();

            //Create the farm root node
            TreeNode FarmNode = new TreeNode(FarmObj.Name);
            FarmNode.ImageIndex = 42;
            FarmNode.Checked = true;
            FarmNode.Tag = SPdalHelper.PopulateFarm(FarmObj);
            treeViewSites.Nodes.Add(FarmNode);

            foreach (SPWebApplication wa in CurrentFarm.WebApplications)
            {
                TreeNode App = new TreeNode(wa.Name);
                //Web application icon
                App.ImageIndex = 39;
                App.Checked = true;
                App.Tag = SPdalHelper.PopulateApplication(wa);
                LoadSiteCollections(wa, App,false,0);
                FarmNode.Nodes.Add(App);
                AppCount++;
            }
            ApplicationsLoaded = true;
            UpdatingNode = false;
            UpdateSiteCount();
        }
        private void LoadSiteCollections()
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The local farm is not loaded yet. Please load the farm SharePoint applications first.");
            SPWebService CurrentFarm = SPWebService.ContentService;
            SPFarm FarmObj = SPFarm.Local;

            if (CurrentFarm == null || FarmObj == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));
            UpdatingNode = true;

            foreach (TreeNode AppNode in treeViewSites.Nodes[0].Nodes)
            {
                //Skip unchecked nodes
                if (!AppNode.Checked)
                    continue;
                LoadSiteCollections(CurrentFarm.WebApplications[AppNode.Text], AppNode, false, 0);
            }
            UpdatingNode = false;
            UpdateSiteCount();
        }
        private void buttonLoadSites_Click(object sender, EventArgs e)
        {
            string ErrorMessage = "Error connecting to the local SharePoint farm. The farm is not available or you don't have enough access to load the sites";
            try
            {
                LoadFarm();
            }
            catch (Exception Ex)
            {
                MessageBox.Show(ErrorMessage + string.Format("Error details:{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                            "Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            UpdateSiteCount();
        }
        private void UpdateSiteCount()
        {
            labelSelectedSites.Text = string.Format("( {0} \\ {1} )", SelectedSiteCount, SiteCount);
            GUIcontroler();
        }
        private void GUIcontroler()
        {
            if (AppCount > 0 && SiteCount <= 0)
                loadSiteCollectionsToolStripMenuItem.Enabled = true;
            if(AppCount <= 0 || SiteCount > 0) 
                loadSiteCollectionsToolStripMenuItem.Enabled = false;
            
        }
        private string GetSPObjectProperty(TreeNode Node, string PropertyName)
        {
            string Value = "";
            if (Node != null && Node.Tag is SPObject)
            {
                SPObject spObj = Node.Tag as SPObject;
                if (spObj != null)
                {
                    if (spObj.Properties != null && 
                        spObj.Properties.ContainsKey(PropertyName) &&
                        spObj.Properties[PropertyName] != null)
                    {
                        Value = spObj.Properties[PropertyName];
                    }
                }
            }
            return Value;
        }
        private void GenerateUserReport(bool EntryForSiteCollections, bool EntryForSubSites)
        {
            //Check if the farm node is loaded or not
            if (treeViewSites.Nodes.Count == 0) return;

            //Generate a user report
            #region Generate the user report
            listBoxUsersList.Items.Clear();
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App,false,0);
                }
                foreach (TreeNode SiteCollection in App.Nodes)
                {
                    if (!SiteCollection.Checked)
                        continue;
                    string SiteCollectionUrl = GetSPObjectProperty(SiteCollection,"Url");
                    if (string.IsNullOrEmpty(SiteCollectionUrl)) continue;
                    using (SPSite site = new SPSite(SiteCollectionUrl))
                    {
                        spuManagerObj.GetSiteUsers(site.RootWeb, false, false);
                        if (EntryForSubSites)
                        {
                            bool Retry = true;
                            while (Retry)
                            {
                                Retry = false;
                                string WebTitle = "";
                                string WebUrl = "";
                                try
                                {

                                    using (SPWeb web = site.OpenWeb())
                                    {
                                        WebTitle = web.Title;
                                        WebUrl = web.Url;
                                        spuManagerObj.GetWebUsers(web, null);
                                    }
                                }
                                catch (Exception Ex)
                                {
                                    DialogResult Result = MessageBox.Show(string.Format("Error loading sites under site collection '{0}' Url='{1}'."
                                    + "\n\nMake sure you have access to the site or exclude it from the process in future runs to" +
                                    " avoid interruption.\n\nError details:\n {2}\n\nStack trace:\n {3}\n\n Do you want to:\n" +
                                    "(Retry=)Try again.\n(Abort=)Exit the Process.\n Or ignore this site and continue?", WebTitle, WebUrl,
                                    Ex.Message, Ex.StackTrace), "Error writing file", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error);
                                    if (Result == System.Windows.Forms.DialogResult.Retry)
                                        Retry = true;
                                    else if (Result == System.Windows.Forms.DialogResult.Abort)
                                    {
                                        MessageBox.Show("Process has been aborted by user!");
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
                tabMain.SelectedIndex = 2;
            }
            //Update the list view
            foreach (object user in spuManagerObj.Users.Keys)
            {
                listBoxUsersList.Items.Add(user);
            }
            //Update the unique users count
            labelUsersCount.Text = string.Format("( {0} )", listBoxUsersList.Items.Count);
            #endregion

            #region Save users to a CSV file

            try
            {
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    spuManagerObj.WriteUserDataToCSVFile(saveFileDialogMain.FileName, EntryForSiteCollections, EntryForSubSites);
                }
            }
            catch (Exception Ex)
            {

                MessageBox.Show(string.Format("Error writing the users list to the disk.\nError details: {0}\nStack trace: {1}",
                    Ex.Message, Ex.StackTrace), "Error writing file", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            #endregion

            MessageBox.Show("Users report has beeen created successfully", "Users Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        private void treeViewSites_AfterCheck(object sender, TreeViewEventArgs e)
        {
            if (UpdatingNode) return;
            UpdatingNode = true;
            TreeNode node = e.Node;

            //if Application node
            if (IsFarm(node))
            {
                //select children
                foreach (TreeNode App in node.Nodes)
                {
                    foreach (TreeNode item in App.Nodes)
                    {
                        if (item.Tag is SPObject)
                        {
                            item.Checked = !item.Checked;
                            if(item.Checked)
                                SelectedSiteCount++;
                            else
                                SelectedSiteCount--;
                        }
                    }
                }

            }
            //if Application node
            if (IsApplication(node))
            {
                //select children
                foreach (TreeNode item in node.Nodes)
                {
                    if (item.Tag is SPObject)
                    {
                        item.Checked = !item.Checked;
                        if (item.Checked)
                            SelectedSiteCount++;
                        else
                            SelectedSiteCount--;
                    }
                }

            }
            //if Application node
            if (IsSiteCollection(node))
            {
                if (node.Checked)
                    SelectedSiteCount++;
                else
                    SelectedSiteCount--;
            }

            if (node.Parent != null)
                node.Parent.Checked = true;

            UpdateSiteCount();
            UpdatingNode = false;
        }
        public void UpdateSiteCount(TreeView SitesTree)
        {
            bool SiteSelected = false;
            foreach (TreeNode App in SitesTree.Nodes)
            {
                SiteSelected = false;
                foreach (TreeNode siteurl in App.Nodes)
                {
                    SiteCount++;
                    if (siteurl.Checked)
                    {
                        SelectedSiteCount++;
                        SiteSelected = true;
                    }
                }
                UpdatingNode = true;
                if (SiteSelected)
                    App.Checked = true;
                else
                    App.Checked = false;
                UpdatingNode = false;
            }
            labelSelectedSites.Text = string.Format("( {0} \\ {1} )", SelectedSiteCount, SiteCount);
            GUIcontroler();
        }
        public bool IsFarm(TreeNode Node)
        {
            if (Node != null &&
                Node.Tag != null &&
                Node.Tag is SPObject)
                return GetSPObjectType(Node.Tag as SPObject) == SPType.Farm;
            return false;
        }
        public bool IsApplication(TreeNode Node)
        {
            if (Node != null &&
                Node.Tag != null &&
                Node.Tag is SPObject)
                return GetSPObjectType(Node.Tag as SPObject) == SPType.Application;
            return false;
        }
        public bool IsSiteCollection(TreeNode Node)
        {
            if (Node != null &&
                Node.Tag != null &&
                Node.Tag is SPObject)
                return GetSPObjectType(Node.Tag as SPObject) == SPType.SiteCollection;
            return false;
        }
        public SPType GetSPObjectType(SPObject spObj)
        {
            if (spObj != null)
                return spObj.WSSType;
            return SPType.Undefined;
        }
       
        private void treeViewSites_BeforeCheck(object sender, TreeViewCancelEventArgs e)
        {
            TreeNode node = e.Node;
            if (!(node.Tag is SPObject)) e.Cancel = true;
        }
        private void buttonSaveSites_Click(object sender, EventArgs e)
        {
            DataTable SiteData = null;
            try
            {
                //SiteData = GetSitesDataWithStorageInfo();
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error creating a site collection report.\nError details: {0}\nStack trace: {1}",
                   Ex.Message, Ex.StackTrace), "Error getting the site collections info", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            try
            {
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    spuManagerObj.WriteDataTableToFile(saveFileDialogMain.FileName, SiteData);
                    MessageBox.Show("Site collection data with their admin has been written successfully to the selected file.",
                                    "Export user to CSV file", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception Ex)
            {

                MessageBox.Show(string.Format("Error writing the site collection data to the disk.\nError details: {0}\nStack trace: {1}",
                    Ex.Message, Ex.StackTrace), "Error writing file", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private DataTable GetSitesDataWithStorageInfo(int IncreaseStorage,bool AutoIncreaseStorageQuota)
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("No farm is loaded. Please load the farm SharePoint applications first.");
            DataTable Results = new DataTable("Site Collections");
            Results.Columns.Add("I");
            Results.Columns.Add("URL");
            Results.Columns.Add("Site Quota (MB)");
            Results.Columns.Add("Site Size (MB)");
            Results.Columns.Add("Quota Limit Increase Value (MB)");
            int I = 1;
            
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                bool SitesQuotaUpdated = false;
                if (!App.Checked)
                    continue;
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App, AutoIncreaseStorageQuota,IncreaseStorage);
                    SitesQuotaUpdated = true;
                }
                foreach (TreeNode siteNode in App.Nodes)
                {
                    if (!siteNode.Checked)
                        continue;
                    bool ApproachedLimit = GetSPObjectProperty(siteNode, "C: Quota Approached Limit") == "True";
                    DataRow newAdminEntry = Results.NewRow();
                    newAdminEntry["I"] = I++;
                    newAdminEntry["Url"] = siteNode.Text;
                    newAdminEntry["Site Quota (MB)"] = GetSPObjectProperty(siteNode, "C: Quota(MB)");
                    newAdminEntry["Site Size (MB)"] = GetSPObjectProperty(siteNode, "C: Storage(MB)");
                    if (ApproachedLimit)
                        newAdminEntry["Quota Limit Increase Value (MB)"] = IncreaseStorage;
                    else
                        newAdminEntry["Quota Limit Increase Value (MB)"] = 0;
                   
                    //Update site quota
                    if (AutoIncreaseStorageQuota &&
                        IncreaseStorage > 0 &&
                        !SitesQuotaUpdated &&
                        ApproachedLimit)
                    {
                        using (SPSite site = new SPSite(siteNode.Text))
                        {
                            while (true)
                            {
                                try
                                {
                                    SPUmanager.UpdateSiteQuota(site, IncreaseStorage);
                                    break;
                                }
                                catch (Exception Ex)
                                {
                                    DialogResult Result = MessageBox.Show(string.Format("Unable to increase the site quota for the site collection {0}.\n\n Error Details:\n{1}", site.Url, Ex.Message),
                                        "Increase site collection quota", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error);
                                    if (Result == System.Windows.Forms.DialogResult.Abort)
                                    {
                                        throw;
                                    }
                                    else if (Result == System.Windows.Forms.DialogResult.Ignore)
                                    {
                                        newAdminEntry["Quota Limit Increase Value (MB)"] = "0 - Failed to increase quota";
                                        break;
                                    }

                                }
                            }
                        }
                    }
                    //Add entry to the table
                    Results.Rows.Add(newAdminEntry);
                }
            }

            
            return Results;
        }
        private DataTable GetSiteAdministratorsData()
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The farm is not loaded yet. Please load the applications in the farm first.");
            DataTable Results = new DataTable("Site Collections");
            Results.Columns.Add("I");
            Results.Columns.Add("URL");
            Results.Columns.Add("Admin Name");
            Results.Columns.Add("Admin NTID");
            Results.Columns.Add("Admin Email");
            int I = 1;
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App,false,0);
                }
                foreach (TreeNode siteurl in App.Nodes)
                {
                    if (!siteurl.Checked)
                        continue;
                    if (siteurl.Nodes.ContainsKey("Admins"))
                    {
                        foreach (TreeNode admin in siteurl.Nodes["Admins"].Nodes)
                        {
                            DataRow newAdminEntry = Results.NewRow();
                            newAdminEntry["I"] = I++;
                            newAdminEntry["Url"] = siteurl.Text;
                            //Get the admin properties
                            newAdminEntry["Admin Name"] = GetSPObjectProperty(admin, "Name");
                            newAdminEntry["Admin NTID"] = GetSPObjectProperty(admin, "LoginName");
                            newAdminEntry["Admin Email"] = GetSPObjectProperty(admin, "Email");
                            //Add entry to the table
                            Results.Rows.Add(newAdminEntry);

                        }
                    }
                }
            }
            return Results;
        }
        private DataTable GenerateLastModifiedDateReport()
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The farm is not loaded yet. Please load the applications in the farm first.");
            DataTable Results = new DataTable("Site Collections");
            Results.Columns.Add("I");
            Results.Columns.Add("Url");
            Results.Columns.Add("Last Content Modified Date");
            Results.Columns.Add("Last Security Modified Date");
            int I = 1;
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App, false, 0);
                }
                foreach (TreeNode SiteNode in App.Nodes)
                {
                    if (!SiteNode.Checked)
                        continue;

                    DataRow newAdminEntry = Results.NewRow();
                    newAdminEntry["I"] = I++;
                    newAdminEntry["Url"] = SiteNode.Text;
                    newAdminEntry["Last Content Modified Date"] = GetSPObjectProperty(SiteNode, "LastContentModifiedDate");
                    newAdminEntry["Last Security Modified Date"] = GetSPObjectProperty(SiteNode, "LastSecurityModifiedDate");
                    //Add entry to the table
                    Results.Rows.Add(newAdminEntry);
                }
            }
            return Results;
        }
        private DataTable GenerateLastAccessedDateReport()
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The farm is not loaded yet. Please load the applications in the farm first.");
            DataTable Results = new DataTable("Site Collections");
            Results.Columns.Add("I");
            Results.Columns.Add("Url");
            Results.Columns.Add("Last Accessed Date");
            Results.Columns.Add("Enough Auditing Enabled");
            int I = 1;
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App, false, 0);
                }
                foreach (TreeNode SiteNode in App.Nodes)
                {
                    if (!SiteNode.Checked)
                        continue;
                    string SiteCollectionUrl = SiteNode.Text;
                    using (SPSite site = new SPSite(SiteCollectionUrl))
                    {
                        DataRow newAuditEntry = Results.NewRow();
                        newAuditEntry["I"] = I++;
                        newAuditEntry["Url"] = SiteCollectionUrl;
                        try
                        {
                            //Check if auditing is set to capture enough information
                            if (EnoughAuditingIsEnabled(site))
                            {
                                newAuditEntry["Enough Auditing Enabled"] = "True";
                                DateTime? LastAccessedDate = GetLastDateSiteWasAccessed(site);
                                if (LastAccessedDate != null)
                                {
                                    newAuditEntry["Last Accessed Date"] = LastAccessedDate;
                                }
                            }
                            else
                            {
                                newAuditEntry["Last Accessed Date"] = "";
                                newAuditEntry["Enough Auditing Enabled"] = "False";
                            }
                        }
                        catch (UnauthorizedAccessException)
                        {
                            newAuditEntry["Last Accessed Date"] = "Access Denied";
                            newAuditEntry["Enough Auditing Enabled"] = "Access Denied";
                        }
                        catch (Exception Ex)
                        {
                            newAuditEntry["Last Accessed Date"] = "Error - " + Ex.Message;
                            newAuditEntry["Enough Auditing Enabled"] = "Error - " + Ex.Message;
                        }
                        //Add entry to the table
                        Results.Rows.Add(newAuditEntry);
                    }
                    
                }
            }
            return Results;
        }
        private void treeViewSites_AfterSelect(object sender, TreeViewEventArgs e)
        {
            lsvLists.Items.Clear();
            if (e.Node.Tag == null) return;
            if (e.Node.Tag.GetType() == typeof(SPObject))
            {
                SPObject NodeData = e.Node.Tag as SPObject;
                if (NodeData.WSSType == SPType.Undefined && e.Node.Text == "Audit")
                {
                    dgvItems.DataSource = NodeData.Data;
                    tabMain.TabPages[1].Text = "Audit Log";
                    tabMain.SelectedIndex = 1;
                }
                else
                {

                    //Load properties page
                    SPObject SelectedSPObj = (SPObject)e.Node.Tag;
                    LoadPropertiesPage(SelectedSPObj);
                }
            }
            
        }

        private void LoadPropertiesPage(SPObject SelectedSPObj)
        {
            //Load properties page

            foreach (var ValuePair in SelectedSPObj.Properties)
            {
                lsvLists.Items.Add(ValuePair.Key).SubItems.Add(ValuePair.Value);
            }
            lsvLists.Sorting = SortOrder.Ascending;
            lsvLists.Sort();
            tabMain.SelectedIndex = 0;
        }

        private void toolStripButtonConnectToSharePoint_Click(object sender, EventArgs e)
        {
            try
            {
                LoadApps();
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error connection to SharePoint.\nError details: {0}\nStack trace: {1}",
                  Ex.Message, Ex.StackTrace), "Connecting to local farm ...", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void treeViewSites_DoubleClick(object sender, EventArgs e)
        {
            if (treeViewSites.SelectedNode == null) return;

            TreeNode SelectedNode = treeViewSites.SelectedNode;
            if (SelectedNode.Nodes.Count <= 0)
            {
                if (SelectedNode.Tag != null && SelectedNode.Tag.GetType() == typeof(SPObject))
                {
                    SPObject NodeData = SelectedNode.Tag as SPObject;
                    if (NodeData.WSSType == SPType.Application)
                    {
                        LoadAppNodeSiteCollections(NodeData.ID, SelectedNode,false,0);
                    }
                    else if (NodeData.WSSType == SPType.Undefined && SelectedNode.Text.StartsWith("Audit"))
                    {
                        bool AccessDeniedBefore = SelectedNode.Text.Contains("Access Denied");
                        //Load audit data if not loaded
                        if (NodeData.Data != null && NodeData.Data.Columns.Count > 0)
                        {
                            dgvItems.DataSource = NodeData.Data;
                            tabMain.TabPages[1].Text = "Audit Log";
                            tabMain.SelectedIndex = 1;
                        }
                        else
                        {
                            try
                            {
                                using (SPSite site = new SPSite(new Guid(NodeData.ID)))
                                {
                                    DataTable AuditLog = GetAuditLog(site);
                                    NodeData.Data = AuditLog;
                                    dgvItems.DataSource = AuditLog;
                                    tabMain.TabPages[1].Text = "Audit Log";
                                    tabMain.SelectedIndex = 1;
                                    //Remove access denied label if any
                                    SelectedNode.Text = "Audit";
                                }
                            }
                            catch (UnauthorizedAccessException)
                            {
                                if (AccessDeniedBefore)
                                {
                                    MessageBox.Show("Access denied. Make sure you have site administrator rights to be able to view the audit log.",
                                                    "Load Audit Log", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                }
                                else
                                    SelectedNode.Text += " (Access Denied)";
                            }
                            catch (Exception Ex)
                            {
                                MessageBox.Show("Unable to load audit data." + Ex.Message);
                            }
                        }
                        
                    }
                }
            }
        }
        private SPUser GetUserbyID(int ID,SPSite site)
        {
            if(ID < 0)
                return null;
            SPUser user = null;
            try
            {
                user = site.RootWeb.SiteUsers[ID];
            }
            catch
            { }
            return user;
        }
        private bool EnoughAuditingIsEnabled(SPSite site)
        {
            return ((site.Audit.AuditFlags & SPAuditMaskType.View) == SPAuditMaskType.View);
        }
        private DateTime? GetLastDateSiteWasAccessed(SPSite site)
        {
            //Prepare audit query object for the site collection
            SPAuditQuery AuditQuery = new SPAuditQuery(site);

            //Restrict query only to view events
            AuditQuery.AddEventRestriction(SPAuditEventType.View);

            //Get all view events for the site collection
            SPAuditEntryCollection AuditLog = site.Audit.GetEntries(AuditQuery);

            //Sort view events descending and return the last view date
            List<DateTime> ViewLogsSorted = (from SPAuditEntry AE in AuditLog
                          orderby AE.Occurred descending
                          select AE.Occurred).ToList();
            if (ViewLogsSorted != null && ViewLogsSorted.Count > 0)
                return ViewLogsSorted[0];
            return null;
        }
        private DataTable GetAuditLog(SPSite site)
        {
            //Cache fetched users in this collection
            Dictionary<int, string> Users = new Dictionary<int, string>();

            //Add system accounts
            Users.Add(1073741823, "System Account;System Account");
            Users.Add(9, "System Account;System Account"); //TODO: Confirm that 9 is the system account

            //Prepare the table to populate with audit data
            DataTable Audit = new DataTable();
            Audit.Columns.Add("Document Location");
            Audit.Columns.Add("Event Type");
            Audit.Columns.Add("Event Data");
            Audit.Columns.Add("Event Name");
            Audit.Columns.Add("Event Source");
            Audit.Columns.Add("Item Id");
            Audit.Columns.Add("Item Type");
            Audit.Columns.Add("Location Type");
            Audit.Columns.Add("Occurred",typeof(DateTime));
            Audit.Columns.Add("Site Id");
            Audit.Columns.Add("Source Name");
            Audit.Columns.Add("User Id",typeof(int));
            Audit.Columns.Add("User NTID");
            Audit.Columns.Add("User Name");
            Audit.Columns.Add("Machine IP");
            Audit.Columns.Add("Machine Name");
            SPAuditEntryCollection AuditLog = site.Audit.GetEntries();
            //Sort view events descending and return the last view date
            var AuditLogsSorted = from SPAuditEntry AE in AuditLog
                                             orderby AE.Occurred descending
                                             select AE;
            int PreviousUserID = -1;
            string PreviousUserLogin = "";
            string PreviousUserName = "";

            foreach (var audit in AuditLogsSorted)
            {
                
                DataRow DR = Audit.NewRow();
                DR["Document Location"] = audit.DocLocation;
                DR["Event Type"] = audit.Event;
                DR["Event Data"] = audit.EventData;
                DR["Event Name"] = audit.EventName;
                DR["Event Source"] = audit.EventSource;
                DR["Item Id"] = audit.ItemId;
                DR["Item Type"] = audit.ItemType;
                DR["Location Type"] = audit.LocationType;
                DR["Machine IP"] = audit.MachineIP;
                DR["Machine Name"] = audit.MachineName;
                DR["Occurred"] = audit.Occurred;
                DR["Site Id"] = audit.SiteId;
                DR["Source Name"] = audit.SourceName;
                int UserID = audit.UserId;
                DR["User Id"] = UserID;
                //Get user info from quick cache
                if (UserID == PreviousUserID)
                {
                    DR["User NTID"] = PreviousUserLogin;
                    DR["User Name"] = PreviousUserName;
                }//Get from the regular cache
                else if (Users.ContainsKey(UserID))
                {
                    string[] UserInfo = Users[UserID].Split(';');
                    PreviousUserID = UserID;
                    DR["User NTID"] = PreviousUserLogin = UserInfo[0];
                    DR["User Name"] = PreviousUserName = UserInfo[1];
                }
                else //Not found in cache
                {
                    //Get user from site
                    SPUser user = GetUserbyID(UserID, site);
                    if (user != null)
                    {
                        //store in cache
                        Users.Add(UserID, user.LoginName + ";" + user.Name);
                        PreviousUserID = UserID;
                        DR["User NTID"] = PreviousUserLogin = user.LoginName;
                        DR["User Name"] = PreviousUserName = user.Name;
                    }
                    else
                    {
                        //Store empty user in cache to avoid trying to fetch it again from site
                        Users.Add(UserID," ; ");
                    }
                }
                Audit.Rows.Add(DR);
            }
            return Audit;
        }
        private void LoadAppNodeSiteCollections(string ApplicationID, TreeNode AppNode,bool AutoIncreaseStorageQuota, int QuotaIncrease)
        {
            SPWebService CurrentFarm = SPWebService.ContentService;
            if (CurrentFarm == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));
            UpdatingNode = true;
            SPWebApplication WebApp = CurrentFarm.WebApplications[new Guid(ApplicationID)];
            LoadSiteCollections(WebApp, AppNode, AutoIncreaseStorageQuota, QuotaIncrease);
            UpdatingNode = false;
        }
        private void LoadSiteCollections(SPWebApplication WebApp,TreeNode AppNode, bool AutoIncreaseStorageQuota,int QuotaIncreaseValue)
        {
            UpdatingNode = true;
            TreeNode SiteNode = null;
            foreach (SPSite sc in WebApp.Sites)
            {
                SiteCount++;
                string Error = "";
                bool QuotaClose = false;
                try
                {
                    //Test the site access
                    DateTime LastModified = sc.RootWeb.LastItemModifiedDate;
                    SiteNode = new TreeNode(sc.Url);
                    SiteNode.Checked = true;
                    //Site Collections
                    SiteNode.ImageIndex = 21;

                    //Add Site collection Admins
                    if (sc.RootWeb.SiteAdministrators.Count > 0)
                    {
                        TreeNode Admins = SiteNode.Nodes.Add("Admins");
                        //Admins icon
                        Admins.ImageIndex = 40;
                        Admins.Name = "Admins";
                        int Increase = 0;
                        if (sc.Quota.StorageMaximumLevel > 0 &&
                            sc.Usage.Storage >= sc.Quota.StorageWarningLevel)
                        {
                            if(AutoIncreaseStorageQuota)
                                Increase = QuotaIncreaseValue;

                            QuotaClose = true;
                        }
                        long Quota = sc.Quota.StorageMaximumLevel / Convert.ToInt64(1024 * 1024);
                        long Storage = sc.Usage.Storage / Convert.ToInt64(1024 * 1024);
                        //Update site collection storage info
                        SPObject SiteCollection = SPdalHelper.PopulateSiteCollection(sc);
                        SiteCollection.Properties.Add("C: Quota(MB)", Quota.ToString());
                        SiteCollection.Properties.Add("C: Storage(MB)", Storage.ToString());
                        SiteCollection.Properties.Add("C: Increase(MB)", Increase.ToString());
                        SiteCollection.Properties.Add("C: Quota Approached Limit", QuotaClose?"True":"False");
                        SiteNode.Tag = SiteCollection;

                        foreach (SPUser admin in sc.RootWeb.SiteAdministrators)
                        {
                            TreeNode tempadmin = Admins.Nodes.Add(admin.Name + " (" + admin.LoginName + ")");
                            //User Icon
                            tempadmin.ImageIndex = 37;
                            tempadmin.Tag = SPdalHelper.PopulateUser(admin);
                        }
                    }
                    //Update Quotas
                    if (AutoIncreaseStorageQuota && QuotaClose)
                    {
                        SPUmanager.UpdateSiteQuota(sc, QuotaIncreaseValue);
                    }

                    //Add audit data
                    TreeNode Audit = SiteNode.Nodes.Add("Audit");
                    //Audit icon
                    Audit.ImageIndex = 43;
                    Audit.Name = "Audit";
                    Audit.Tag = new SPObject("Site", sc.ID, SPType.Undefined);



                    SelectedSiteCount++;
                }
                catch (Exception Ex)
                {
                    Error = " [Error]:" + Ex.Message;
                    SiteNode = new TreeNode(sc.Url + Error);
                    SiteNode.Checked = false;
                    SiteNode.Tag = false;
                    SiteNode.ImageIndex = 41;
                }
                AppNode.Nodes.Add(SiteNode);
                sc.Dispose();
            }
            UpdatingNode = false;
            UpdateSiteCount();
        }

        private void loadAppsOnlyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (new HourGlass())
            {
                try
                {
                    LoadApps();
                    tabMain.SelectedIndex = 0;
                }
                catch (Exception Ex)
                {
                    MessageBox.Show(string.Format("Error connection to SharePoint.\nError details: {0}\nStack trace: {1}",
                      Ex.Message, Ex.StackTrace), "Connecting to local farm ...", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void loadFarmToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (new HourGlass())
            {
                try
                {
                    LoadFarm();
                    tabMain.SelectedIndex = 0;
                }
                catch (Exception Ex)
                {
                    MessageBox.Show(string.Format("Error connection to SharePoint.\nError details: {0}\nStack trace: {1}",
                      Ex.Message, Ex.StackTrace), "Connecting to local farm ...", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void usersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Create report info object
            SPReport ReportData = new SPReport();
            ReportData.Name = "SharePoint Users Report";
            ReportData.Settings.Add("Add a record for each site collection", true);
            ReportData.Settings.Add("Add a record for each sub site", true);


            //Create a new report form
            try
            {
                ReportMain ReportForm = new ReportMain();
                ReportForm.ReportData = ReportData;
                if (ReportForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    bool EntryForSiteCollection = ReportForm.ReportData.Settings["Add a record for each site collection"];
                    bool EntryForEachSubSite = ReportForm.ReportData.Settings["Add a record for each sub site"];
                    GenerateUserReport(EntryForSiteCollection, EntryForEachSubSite);
                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error creating users report. Error details:{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                            "Generate User Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            
        }

        private void siteAdministratorsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (new HourGlass())
            {
                //Create a new report form
                try
                {
                    if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        using (new HourGlass())
                        {
                            DataTable SiteData = null;
                            SiteData = GetSiteAdministratorsData();
                            spuManagerObj.WriteDataTableToFile(saveFileDialogMain.FileName, SiteData);
                        }
                        MessageBox.Show("Site collection data with their admin has been written successfully to the selected file.",
                                        "Generate Site Administrators Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
                catch (Exception Ex)
                {
                    MessageBox.Show(string.Format("Error creating site administrators report. Error details:{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                                "Generate Site Administrators Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void quotaStorageToolStripMenuItem_Click(object sender, EventArgs e)
        {

            //Create report info object
            string StorageIncreaseBoolSettingStr = "Increase site collection quotas which reached the storage warning limit with the value below:";
            SPReport ReportData = new SPReport();
            ReportData.Name = "SharePoint Site Storage Report";
            ReportData.Settings.Add(StorageIncreaseBoolSettingStr, false);
            ReportData.Properties.Add("IncreaseValue", new ReportProperty(true, "1", "Increase value by (GB)"));
            ReportData.DisplayUpdateWarning = true;
            ReportData.UpdateWarning = "This report might increase the site storage quotas for the selected site collections depending on the settings you have selected.";


            //Create a new report form
            try
            {
                ReportMain ReportForm = new ReportMain();
                ReportForm.ReportData = ReportData;
                if (ReportForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    DataTable SiteData = null;
                    using (new HourGlass())
                    {
                        bool IncreaseStorageAutomaticlly = ReportForm.ReportData.Settings[StorageIncreaseBoolSettingStr];
                        string IncreaseValue = ReportForm.ReportData.Properties["IncreaseValue"].Value;

                        //Convert from GB to MB
                        SiteData = GetSitesDataWithStorageInfo(Convert.ToInt16((decimal.Parse(IncreaseValue) * 1024)), IncreaseStorageAutomaticlly);
                    }
                    if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        using (new HourGlass())
                        {
                            spuManagerObj.WriteDataTableToFile(saveFileDialogMain.FileName, SiteData);
                        }
                        MessageBox.Show("Site collection data with storage info repot has been generated successfully",
                                        "Generate Site Collection Storage Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }

                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error generating site collection storage report. Error details:{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                            "Generate Site Collection Storage Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void openAccessToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Create report info object
            SPReport ReportData = new SPReport();
            ReportData.Name = "Open Access Report";
            ReportData.Settings.Add("Scan SharePoint lists", true);
            ReportData.Settings.Add("Scan list items", false);
            ReportData.Settings.Add("Scan objects with unique permissions only", true);
            ReportData.Settings.Add("Exclude system lists", true);


            //Create a new report form
            try
            {
                ReportMain ReportForm = new ReportMain();
                ReportForm.ReportData = ReportData;
                if (ReportForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    DataTable Permissions = null;
                    using (new HourGlass())
                    {
                        bool ScanLists = ReportForm.ReportData.Settings["Scan SharePoint lists"];
                        bool ScanListItems = ReportForm.ReportData.Settings["Scan list items"];
                        bool IncludeObjWithUniquePermOnly = ReportForm.ReportData.Settings["Scan objects with unique permissions only"];
                        bool ExcludeSystemLists = ReportForm.ReportData.Settings["Exclude system lists"];
                        Permissions = GenerateOpenAccessReport(ScanLists, ScanListItems, IncludeObjWithUniquePermOnly, ExcludeSystemLists);
                    }
                        if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                        {
                            using (new HourGlass())
                            {
                                spuManagerObj.WriteDataTableToFile(saveFileDialogMain.FileName, Permissions);
                            }
                            MessageBox.Show("Open access repot has been generated successfully",
                                            ReportData.Name, MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }
                    
                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error creating open access report report.\n\nError details:\n{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                            ReportData.Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private DataTable GenerateOpenAccessReport(bool CheckLists, bool CheckListItems, bool ReportListssWithUniquePermissionsOnly, bool RemoveSystemLists)
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The farm is not loaded yet. Please load the farm SharePoint applications first.");
            DataTable Results = SPUmanager.InitializePermissionsTable();
            int I = 1;
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App, false, 0);
                }
                foreach (TreeNode siteurl in App.Nodes)
                {
                    if (!siteurl.Checked)
                        continue;
                    DataTable sitePermissions = GetOpenAccessForSite(siteurl.Text, CheckLists, CheckListItems, ReportListssWithUniquePermissionsOnly, RemoveSystemLists);
                    if(sitePermissions != null)
                        Results.Merge(sitePermissions, true, MissingSchemaAction.Add);
                }
            }
            return Results;
        }
        private DataTable GetOpenAccessForSite(string siteCollectionUrl,bool CheckLists, bool CheckListItems, bool ReportListssWithUniquePermissionsOnly, bool RemoveSystemLists)
        {
            DataTable Permissions = SPUmanager.InitializePermissionsTable();
            //Exclude the User Information List
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite SiteCollection = new SPSite(siteCollectionUrl))
                {
                    foreach (SPWeb web in SiteCollection.AllWebs)
                    {
                        try
                        {
                            DataTable webPermissions = SPUmanager.GetNtAuthenticatedUsersPermission(web, CheckLists, CheckListItems, ReportListssWithUniquePermissionsOnly, RemoveSystemLists);
                            if(webPermissions != null)
                                Permissions.Merge(webPermissions, true, MissingSchemaAction.Add);
                        }
                        finally
                        {
                            if (web != null)
                                web.Dispose();
                        }
                    }
                }
                
            });
            return Permissions;
        }

        private void loadSiteCollectionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (new HourGlass())
            {
                try
                {
                    LoadSiteCollections();
                }
                catch (Exception Ex)
                {
                    MessageBox.Show(string.Format("Error creating open access report report.\n\nError details:\n{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                                "Load site collections", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void lastModifiedDateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    using (new HourGlass())
                    {
                        DataTable SiteData = null;
                        SiteData = GenerateLastModifiedDateReport();
                        spuManagerObj.WriteDataTableToFile(saveFileDialogMain.FileName, SiteData);
                    }
                    MessageBox.Show("Last modified date report has been written successfully to the selected file.",
                                    "Last Modified Date Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error generating the last modified date report.\n\nError details:\n{0}\n\nCall stack:\n{1}", Ex.Message, Ex.StackTrace),
                                            "Last Modified Date Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void lastAccessedDateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    using (new HourGlass())
                    {
                        DataTable SiteData = null;
                        SiteData = GenerateLastAccessedDateReport();
                        spuManagerObj.WriteDataTableToFile(saveFileDialogMain.FileName, SiteData);
                    }
                    MessageBox.Show("Last accessed date report has been written successfully to the selected file.",
                                    "Last Accessed Date Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error generating the last accessed date repor.\n\nError details:\n{0}\n\nCall stack:\n{1}", Ex.Message, Ex.StackTrace),
                                            "Last Accessed Date Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            Helper.CheckIfRunningAsAnAdmin(this);
        }

        
    }


}